package au.edu.qut.bpm.genbinder.genetic.genesis;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

import org.uncommons.watchmaker.framework.factories.AbstractCandidateFactory;

import au.edu.qut.bpm.genbinder.models.AbstractLog;
import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;
import au.edu.qut.bpm.genbinder.models.Resource;

public abstract class LogAbstractFactory extends AbstractCandidateFactory<ConcreteEventLog> {
	public AbstractLog templateLog;
	public ConcreteEventLog cel;

	public LogAbstractFactory(ConcreteEventLog log) {
		templateLog = log.getAbstractLog();
		cel = log;
		/*
		Map<Task, Set<Set<Resource>>> resourceSetCanDoTask = log.getTaskResourceSetMap();
		Set<Resource> resourceSetManager1 = new HashSet<Resource>();
		Set<Resource> resourceSetManager2 = new HashSet<Resource>();
		Set<Resource> resourceSetManager3 = new HashSet<Resource>();
		resourceSetManager1.add(new Resource("IM1"));
		resourceSetManager2.add(new Resource("IM2"));
		resourceSetManager3.add(new Resource("IM3"));
		
		for (Map.Entry<Task, Set<Set<Resource>>> entry : resourceSetCanDoTask.entrySet())
		{
			resourceSetCanDoTask.get(entry.getKey()).add(resourceSetManager1);
			resourceSetCanDoTask.get(entry.getKey()).add(resourceSetManager2);
			resourceSetCanDoTask.get(entry.getKey()).add(resourceSetManager3);
		    
		}
		
		templateLog.setTaskResourceSetMap(resourceSetCanDoTask);
		//*/
	}
	
	public abstract ConcreteEventLog generateRandomCandidate();

	public abstract ConcreteEventLog generateRandomCandidate(Random rng);
	
	public abstract ConcreteEventLog generateRandomCandidate(boolean performSafetyCheck, Random rng);

	public static Set<Resource> getRandomPossibleResourceSetForProposedStartTime(ConcreteEventLog newLog, Activity a, long start, Random rng) {
		Set<Set<Resource>> possible = newLog.getAbstractLog().getTaskResourceSetMap().get(a.getTask());
		Set<Set<Resource>> available = new HashSet<Set<Resource>>(possible);
		Set<Resource> alreadyUsed = newLog.getResourcesUtilizedWithin(start, start + newLog.getActivityDuration(a), a.getCase());

		for (Resource r : alreadyUsed)
			for (Set<Resource> rs : possible)
				if (rs.contains(r))
					available.remove(rs);

		if (available.size() == 0) {
			return null;
		} else {
			int item = rng.nextInt(available.size());
			int i = 0;
			for (Set<Resource> r : available) {
				if (i == item)
					return r;
				i++;
			}
		}

		return null;
	}
	
	public static Set<Resource> getRandomResourceSet(ConcreteEventLog newLog, Activity a, Random rng) {
		Set<Set<Resource>> possible = newLog.getAbstractLog().getTaskResourceSetMap().get(a.getTask());
		int item = rng.nextInt(possible.size());
		int i = 0;
		for (Set<Resource> r : possible) {
			if (i == item)
				return r;
			i++;
		}
		return null;
	}

}
